﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Ndns.Packet.ResourceRecords
{
    public sealed class DnsResourceRecordCNAME : DnsResourceRecord
    {

        /// <summary>
        /// 表示应答中的CNAME记录。
        /// </summary>
        public DnsHostName CanonicalName { get; set; }

        public override DnsRecordType Type { get => DnsRecordType.CNAME; set => throw new NotSupportedException(); }

        /// <summary>
        /// 根据相关信息构造DnsResourceRecordCNAME实例。
        /// </summary>
        /// <param name="hostName">DNS应答的主机名信息。</param>
        /// <param name="c">DNS应答的类别。</param>
        /// <param name="ttl">DNS应答的超时时间。</param>
        /// <param name="canonicalName">DNS应答的数据。</param>
        public DnsResourceRecordCNAME(DnsHostName hostName, DnsClass c, uint ttl, DnsHostName canonicalName)
            : base(hostName, c, ttl)
        {
            CanonicalName = canonicalName ?? throw new ArgumentNullException(nameof(canonicalName));
        }

        /// <summary>
        /// 从包含数据包的流中以支持指针的方式构造实例。
        /// </summary>
        /// <param name="packetStream">数据包流，Position应该指向要解析的应答的开始。</param>
        /// <param name="offset">数据包的开始位置在流中的偏移量。</param>
        /// <returns>解析得到的实例。</returns>
        public static new DnsResourceRecordCNAME FromPacket(Stream packetStream, long packetStartIndex)
        {
            var hostName = DnsHostName.FromPacket(packetStream, packetStartIndex);
            var vType = packetStream.ReadNetworkUInt16();
            var vClass = packetStream.ReadNetworkUInt16();
            var vTTL = packetStream.ReadNetworkUInt32();
            int len = packetStream.ReadNetworkUInt16();
            PacketEndOfStreamException.CheckValue(vType, vClass, len);
            PacketEndOfStreamException.CheckValue(vTTL);

            if ((DnsRecordType)vType != DnsRecordType.CNAME)
                throw new FormatException();

            long pos = packetStream.Position;
            var vAnswer = DnsHostName.FromPacket(packetStream, packetStartIndex);
            packetStream.Seek(pos + len, SeekOrigin.Begin);
            return new DnsResourceRecordCNAME(hostName, (DnsClass)vClass, (uint)vTTL, vAnswer);
        }

        public override DnsResourceRecord Clone()
        {
            return new DnsResourceRecordCNAME(HostName, Class, TTL, CanonicalName);
        }

        public override byte[] GetData()
        {
            return CanonicalName.GetBytes();
        }

        protected override int CopyDataTo(Stream s)
        {
            return CanonicalName.CopyTo(s);
        }

        protected override int CopyCompressedDataTo(Stream s, Dictionary<string, DnsHostNamePointer> symbols, ref int offset)
        {
            return CanonicalName.CopyCompressedTo(s, symbols, ref offset);
        }

        protected override int GetDataHashCode()
        {
            return CanonicalName.GetHashCode();
        }

        protected override bool TestDataEqualsTo(DnsResourceRecord other)
        {
            var record = other as DnsResourceRecordCNAME;
            if (record == null)
                return false;
            return CanonicalName.Equals(record.CanonicalName);
        }

    }
}
